Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\gen\base\union.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::message::Referenced;
30
use crate::compiler::union::{DiscriminantField, Union};
31
use crate::compiler::util::types::{PtrKey, TypeMapper};
32
use crate::gen::base::map::TypePathMapper;
33
use crate::gen::template::hook::TemplateHooks;
34
use crate::gen::template::Template;
35
use itertools::Itertools;
36
use std::collections::HashSet;
37
38
pub trait Utilities: crate::gen::base::structure::Utilities {
39
    fn gen_discriminant_path(discriminant: &DiscriminantField) -> String;
40
    fn gen_discriminant_path_mut(discriminant: &DiscriminantField) -> String;
41
}
42
43
6
fn gen_union_from_slice_impl<T: TypeMapper>(
44
6
    u: &Union,
45
6
    template: &Template,
46
6
    type_path_map: &TypePathMapper<T>,
47
6
    function: &str,
48
6
) -> String {
49
6
    let cases = u
50
6
        .cases
51
6
        .iter()
52
32
        .map(|case| {
53
32
            let mut scope = template.scope();
54
32
            scope.var("name", &case.name).var_d("case", case.case);
55
32
            match &case.item_type {
56
6
                None => scope.render(function, &["none.case"]).unwrap(),
57
26
                Some(item_type) => {
58
26
                    scope.var("type_name", type_path_map.get(item_type)).render(function, &["content.case"]).unwrap()
59
                }
60
            }
61
32
        })
62
6
        .join("");
63
6
    let mut scope = template.scope();
64
6
    scope.var("cases", cases);
65
6
    if u.has_content() {
  Branch (65:8): [True: 4, False: 2]
  Branch (65:8): [True: 0, False: 0]
  Branch (65:8): [Folded - Ignored]
66
4
        scope.render_to_var(function, &["content"], "fragment").unwrap();
67
4
    } else {
68
2
        scope.render_to_var(function, &["none"], "fragment").unwrap();
69
2
    }
70
6
    scope.render("", &[function]).unwrap()
71
6
}
72
73
7
fn gen_union_write_to_impl<T: TypeMapper>(
74
7
    u: &Union,
75
7
    template: &Template,
76
7
    type_path_map: &TypePathMapper<T>,
77
7
    function: &str,
78
7
) -> String {
79
7
    let mut scope = template.scope();
80
7
    if u.has_content() {
  Branch (80:8): [True: 5, False: 2]
  Branch (80:8): [True: 0, False: 0]
  Branch (80:8): [Folded - Ignored]
81
5
        let cases = u
82
5
            .cases
83
5
            .iter()
84
40
            .filter_map(|case| {
85
40
                let mut scope = template.scope();
86
40
                scope.var("name", &case.name).var_d("case", case.case);
87
40
                case.item_type.as_ref().map(|item_type| {
88
37
                    scope.var("type_name", type_path_map.get(item_type)).render(function, &["content.case"]).unwrap()
89
40
                })
90
40
            })
91
5
            .join("");
92
5
        scope.var("cases", cases).render_to_var(function, &["content"], "fragment").unwrap();
93
5
    } else {
94
2
        scope.render_to_var(function, &["none"], "fragment").unwrap();
95
2
    }
96
7
    scope.render("", &[function]).unwrap()
97
7
}
98
99
6
fn gen_union_set_discriminant(u: &Union, template: &Template) -> String {
100
6
    let cases = u
101
6
        .cases
102
6
        .iter()
103
32
        .map(|case| {
104
32
            let mut scope = template.scope();
105
32
            scope.var("name", &case.name).var_d("case", case.case);
106
32
            match &case.item_type {
107
26
                Some(_) => scope.render("setter", &["ref"]).unwrap(),
108
6
                None => scope.render("setter", &["none"]).unwrap(),
109
            }
110
32
        })
111
6
        .join("");
112
6
    template.scope().var("cases", cases).render("", &["setter"]).unwrap()
113
6
}
114
115
6
fn gen_union_as_getters<T: TypeMapper>(u: &Union, template: &Template, type_path_map: &TypePathMapper<T>) -> String {
116
6
    let cases = u
117
6
        .cases
118
6
        .iter()
119
32
        .map(|case| {
120
32
            let mut scope = template.scope();
121
32
            scope.var("name", &case.name);
122
26
            match &case.item_type {
123
22
                Some(Referenced::Struct(v)) => {
124
22
                    scope.var("type_name", type_path_map.get(v)).render("getters", &["struct"]).unwrap()
125
                }
126
4
                Some(Referenced::Message(v)) => {
127
4
                    scope.var("type_name", type_path_map.get(v)).render("getters", &["message"]).unwrap()
128
                }
129
6
                None => scope.render("getters", &["none"]).unwrap(),
130
            }
131
32
        })
132
6
        .join("");
133
6
    template.scope().var("cases", cases).render("", &["getters"]).unwrap()
134
6
}
135
136
6
fn gen_decl<T: TypeMapper>(
137
6
    u: &Union,
138
6
    template: &Template,
139
6
    type_path_map: &TypePathMapper<T>,
140
6
    function: &str,
141
6
) -> String {
142
6
    let cases = u
143
6
        .cases
144
6
        .iter()
145
26
        .map(|case| match &case.item_type {
146
6
            None => template.scope().var("name", &case.name).render(function, &["none"]).unwrap(),
147
22
            Some(Referenced::Struct(v)) => template
148
22
                .scope()
149
22
                .var("name", &case.name)
150
22
                .var("type_name", type_path_map.get(v))
151
22
                .render(function, &["struct"])
152
22
                .unwrap(),
153
4
            Some(Referenced::Message(v)) => template
154
4
                .scope()
155
4
                .var("name", &case.name)
156
4
                .var("type_name", type_path_map.get(v))
157
4
                .render(function, &["message"])
158
4
                .unwrap(),
159
32
        })
160
6
        .join("");
161
6
    template.scope().var("cases", cases).render("", &[function]).unwrap()
162
6
}
163
164
6
fn gen_decl_unique<T: TypeMapper>(
165
6
    u: &Union,
166
6
    template: &Template,
167
6
    type_path_map: &TypePathMapper<T>,
168
6
    function: &str,
169
6
) -> String {
170
6
    let mut found = HashSet::new();
171
6
    let cases = u
172
6
        .cases
173
6
        .iter()
174
26
        .filter_map(|case| match &case.item_type {
175
6
            None => Some(template.scope().var("name", &case.name).render(function, &["none"]).unwrap()),
176
22
            Some(Referenced::Struct(v)) => {
177
22
                if !found.contains(&v.ptr_key()) {
  Branch (177:20): [True: 22, False: 0]
  Branch (177:20): [True: 0, False: 0]
  Branch (177:20): [Folded - Ignored]
178
22
                    found.insert(v.ptr_key());
179
22
                    Some(
180
22
                        template
181
22
                            .scope()
182
22
                            .var("name", &case.name)
183
22
                            .var("type_name", type_path_map.get(v))
184
22
                            .render(function, &["struct"])
185
22
                            .unwrap(),
186
22
                    )
187
                } else {
188
0
                    None
189
                }
190
            }
191
4
            Some(Referenced::Message(v)) => {
192
4
                if !found.contains(&v.ptr_key()) {
  Branch (192:20): [True: 4, False: 0]
  Branch (192:20): [True: 0, False: 0]
  Branch (192:20): [Folded - Ignored]
193
4
                    found.insert(v.ptr_key());
194
4
                    Some(
195
4
                        template
196
4
                            .scope()
197
4
                            .var("name", &case.name)
198
4
                            .var("type_name", type_path_map.get(v))
199
4
                            .render(function, &["message"])
200
4
                            .unwrap(),
201
4
                    )
202
                } else {
203
0
                    None
204
                }
205
            }
206
32
        })
207
6
        .join("");
208
6
    template.scope().var("cases", cases).render("", &[function]).unwrap()
209
6
}
210
211
6
pub fn generate<'variable, U: Utilities, T: TypeMapper>(
212
6
    mut template: Template<'_, 'variable>,
213
6
    u: &'variable Union,
214
6
    type_path_map: &'variable TypePathMapper<T>,
215
6
    hooks: &TemplateHooks,
216
6
) -> String {
217
6
    template
218
6
        .var(
219
6
            "discriminant_raw_type",
220
6
            U::get_field_type(u.discriminant.get_leaf_fixed().bits_type),
221
6
        )
222
6
        .var("union_name", &u.name)
223
6
        .var("discriminant_path_mut", U::gen_discriminant_path_mut(&u.discriminant))
224
6
        .var("discriminant_path", U::gen_discriminant_path(&u.discriminant))
225
6
        .var("discriminant_type", type_path_map.get(&u.discriminant.root));
226
6
    let mut code = gen_decl(u, &template, type_path_map, "decl");
227
6
    for 
func0
in hooks.get_functions("decl") {
228
0
        code += &gen_decl(u, &template, type_path_map, func);
229
0
    }
230
6
    for func in hooks.get_functions("decl_unique") {
231
6
        code += &gen_decl_unique(u, &template, type_path_map, func);
232
6
    }
233
6
    code += &gen_union_from_slice_impl::<T>(u, &template, type_path_map, "from_bytes");
234
6
    for 
func0
in hooks.get_functions("from_bytes") {
235
0
        code += &gen_union_from_slice_impl::<T>(u, &template, type_path_map, func);
236
0
    }
237
6
    code += &gen_union_write_to_impl::<T>(u, &template, type_path_map, "write_to");
238
6
    for 
func1
in hooks.get_functions("write_to") {
239
1
        code += &gen_union_write_to_impl::<T>(u, &template, type_path_map, func);
240
1
    }
241
6
    code += &gen_union_set_discriminant(u, &template);
242
6
    code += &gen_union_as_getters(u, &template, type_path_map);
243
6
    code
244
6
}